﻿
#region Add-Accelerator 

function Add-Accelerator 
{
    <#
    .Synopsis
        Add a type accelerator to the current session
    .Description
        The Add-Accelerator function allows you to add a simple type accelerator (like [regex]) for a longer type (like
    [System.Text.RegularExpressions.Regex]).
    .Example
        Add-Accelerator list System.Collections.Generic.List``1
        $list = New-Object list[string]
        
        Creates an accelerator for the generic List[T] collection type, and then creates a list of strings.
    .Example
        Add-Accelerator "List T", GList System.Collections.Generic.List``1
        $list = New-Object "list t[string]"
        
        Creates two accelerators for the Generic List[T] collection type.
    .Parameter Accelerator
        The short form accelerator should be just the name you want to use (without square brackets).
    .Parameter Type
        The type you want the accelerator to accelerate (without square brackets)
    .Notes
        When specifying multiple values for a parameter, use commas to separate the values. 
        For example, "-Accelerator string, regex".
        
        PowerShell requires arguments that are "types" to NOT have the square bracket type notation, because of the way
    the parsing engine works.  You can either just type in the type as System.Int64, or you can put parentheses around it 
    to help the parser out: ([System.Int64])
    
        Also see the help for Get-Accelerator and Remove-Accelerator
    .Link
        http://huddledmasses.org/powershell-2-ctp3-custom-accelerators-finally/
      
#>
    [CmdletBinding()]
    PARAM(
        [Parameter(Position=0)]
        [Alias("Key")]
        [string[]]$Accelerator,
        
        [Parameter(Position=1)]
        [Alias("Value")]
        [type]$Type
    )
    
    process {
    
        # add a user-defined accelerator  
        foreach($a in $Accelerator) 
        { 
            $xlr8r::Add( $a, $Type) 
            trap [System.Management.Automation.MethodInvocationException] {
                if($xlr8r::get.keys -contains $a) {
                    Write-Error "Cannot add accelerator [$a] for [$($Type.FullName)]`n                  [$a] is already defined as [$($xlr8r::get[$a].FullName)]"
                    Continue;
                } 
                throw
            }
        }
        
    }
}
    
#endregion 


#region Copy-Function 

function Copy-Function
{
        
    <#
        .Synopsis 
            Copy a function from the current session to another session
            
        .Description
            Copies a function deffinition from the current session into any other session
            
        .Parameter Session
            The session(s) you want to define the function in
            
        .Parameter Name
            The Name of the function to copy
            
        .Parameter Definition
            The optional definition of the function. This is used to allow copying via the pipeline.
            
        .Parameter Force
            Overwrite existing functions in the session.
            
        .Parameter Passthru
            Output the FunctionInfo from the session
            
        .Example
            Copy-Function -Session $Session1 -Name Prompt -Force
            Description
            -----------
            Copies the prompt function from the current session into the specified session, overwriting the existing prompt
    function.
        .Example
            Get-Command -Type Function | Copy-Function $Session1
            Description
            -----------
            Copies all of the functions from the current session into the new session.
            
        .Notes
            NAME:      Copy-Function
            AUTHOR:    Jaykul
            Website:   http://huddledmasses.org/
            Version:   1
            #Requires -Version 2.0
            
    #>
        
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
        [Parameter(Mandatory=$true, Position=0)]
        [System.Management.Automation.Runspaces.PSSession[]]
        $Session, 
        
        [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true,Position=1)]
        [String]
        $name, 
        
        [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
        [String]
        $Definition,
        
        [Switch]
        $Force,
        
        [Switch]
        $Passthru
        
    )
    process 
    {
    
        if( $PSCmdlet.ShouldProcess("Copied function $Name to sessions: $(($Session|select -expand Name) -join ', ')","Copy function `"$Name`"?","Copying functions to sessions: $(($Session|select -expand Name) -join ', ')") ) {
            if(!$Definition){ $Definition = (gcm -type function $name).Definition }
            If(!$Passthru) {
                Invoke-Command { 
                    Param($name, $value, $force) 
                    $null = new-item function:"$name" -value $value -force:$force
                } -Session $Session -ArgumentList $Name,$Definition,$Force
            } else {
                Invoke-Command { 
                    Param($name, $value, $force) 
                    new-item function:"$name" -value $value -force:$force
                } -Session $Session -ArgumentList $Name,$Definition,$Force
            }   
        }
        
    }
}
    
#endregion 


#region Format-XML 

function Format-XML
{
    param([xml]$xml, $indent=2)
    $StringWriter = New-Object System.IO.StringWriter 
    $XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter 
    $xmlWriter.Formatting = "indented" 
    $xmlWriter.Indentation = $Indent 
    $xml.WriteContentTo($XmlWriter) 
    $XmlWriter.Flush() 
    $StringWriter.Flush() 
    Write-Output $StringWriter.ToString() 
}
    
#endregion 


#region Get-Accelerator 

function Get-Accelerator
{
        
    <#
        .Synopsis
            Get one or more type accelerator definitions
        .Description
            The Get-Accelerator function allows you to look up the type accelerators (like [regex]) defined on your system 
        by their short form or by type
        .Example
            Get-Accelerator System.String
            
            Returns the KeyValue pair for the [System.String] accelerator(s)
        .Example
            Get-Accelerator ps*,wmi*
            
            Returns the KeyValue pairs for the matching accelerator definition(s)
        .Parameter Accelerator
            One or more short form accelerators to search for (Accept wildcard characters).
        .Parameter Type
            One or more types to search for.
        .Notes
            When specifying multiple values for a parameter, use commas to separate the values. 
            For example, "-Accelerator string, regex".
            
            Also see the help for Add-Accelerator and Remove-Accelerator
        .Link
            http://huddledmasses.org/powershell-2-ctp3-custom-accelerators-finally/
    #>
    
    [CmdletBinding(DefaultParameterSetName="ByType")]
    PARAM(
        [Parameter(Position=0, ParameterSetName="ByAccelerator", ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [Alias("Key")]
        [string[]]$Accelerator,
        
        [Parameter(Position=0, ParameterSetName="ByType", ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [Alias("Value")]
        [type[]]$Type
    )
    
    Process 
    {
    
        # add a user-defined accelerator  
        switch($PSCmdlet.ParameterSetName) {
            "ByAccelerator" { 
                $xlr8r::get.GetEnumerator() | % {
                    foreach($a in $Accelerator) {
                    if($_.Key -like $a) { $_ }
                    }
                }
                break
            }
            "ByType" { 
                if($Type -and $Type.Count) {
                    $xlr8r::get.GetEnumerator() | ? { $Type -contains $_.Value }
                }
                else {
                    $xlr8r::get.GetEnumerator() | %{ $_ }
                }
                break
            }
        }
        
    }
}
    
#endregion 


#region Get-Assemblies 

function Get-Assemblies
{
    [AppDomain]::CurrentDomain.GetAssemblies()
}
    
#endregion 


#region Get-Constructor 

function Get-Constructor
{
    
    PARAM( [Type]$type )
    $type.GetConstructors() | 
    Format-Table @{
        l="$($type.Name) Constructors"
        e={ ($_.GetParameters() | % { $_.ToString() }) -Join ", " }
    }
}
    
#endregion 


#region New-PInvoke 

function New-PInvoke
{
    
    <#
        .Synopsis
            Generate a powershell function alias to a Win32|C api function
        .Description
            Creates C# code to access a C function, and exposes it via a powershell function
        .Example
            New-PInvoke user32 "void FlashWindow(IntPtr hwnd, bool bInvert)"
            
            Generates a function for FlashWindow which ignores the boolean return value, and allows you to make a window fl
    ash to get the user's attention. Once you've created this function, you could use this line to make a PowerShell window
    flash at the end of a long-running script:
    
            C:\PS>FlashWindow (ps -id $pid).MainWindowHandle $true
        .Parameter Library
            A C Library containing code to invoke
        .Parameter Signature
            The C# signature of the external method
        .Parameter OutputText
            If Set, retuns the source code for the pinvoke method.
            If not, compiles the type. 
        #>
        param(
        [Parameter(Mandatory=$true, 
            HelpMessage="The C Library Containing the Function, i.e. User32")]
        [String]
        $Library,
        
        [Parameter(Mandatory=$true,
            HelpMessage="The Signature of the Method, i.e.: int GetSystemMetrics(uint Metric)")]
        [String]
        $Signature,
        
        [Switch]
        $OutputText
        )
    process {
    
            if ($Library -notlike "*.dll*") {
                $Library+=".dll"
            }
            if ($signature -notlike "*;") {
                $Signature+=";"
            }
            if ($signature -notlike "public static extern*") {
                $signature = "public static extern $signature"
            }
            
            $name = $($signature -replace "^.*?\s(\w+)\(.*$",'$1')
            
            $MemberDefinition = "[DllImport(`"$Library`")]`n$Signature"
            
            if (-not $OutputText) {
                $type = Add-Type -PassThru -Name "PInvoke$(Get-Random)" -MemberDefinition $MemberDefinition
                iex "New-Item Function:Global:$name -Value { [$($type.FullName)]::$name.Invoke( `$args ) }"
            } else {
                $MemberDefinition
            }
        
    }
}
    
#endregion 


#region Remove-Accelerator 

function Remove-Accelerator 
{
    
    <#
        .Synopsis 
            Remove a type accelerator from the current session
        .Description
            The Remove-Accelerator function allows you to remove a simple type accelerator (like [regex]) from the current 
        session. You can pass one or more accelerators, and even wildcards, but you should be aware that you can remove even th
        e built-in accelerators.
            
        .Example
            Remove-Accelerator int
            Add-Accelerator int Int64
            
            Removes the "int" accelerator for Int32 and adds a new one for Int64. I can't recommend doing this, but it's pr
        etty cool that it works:
            
            So now, "$(([int]3.4).GetType().FullName)" would return "System.Int64"
        .Example
            Get-Accelerator System.Single | Remove-Accelerator
            
            Removes both of the default accelerators for System.Single: [float] and [single]
        .Example
            Get-Accelerator System.Single | Remove-Accelerator -WhatIf
            
            Demonstrates that Remove-Accelerator supports -Confirm and -Whatif. Will Print:
                What if: Removes the alias [float] for type [System.Single]
                What if: Removes the alias [single] for type [System.Single]
        .Parameter Accelerator
            The short form accelerator that you want to remove (Accept wildcard characters).
        .Notes
            When specifying multiple values for a parameter, use commas to separate the values. 
            For example, "-Accel string, regex".
            
            Also see the help for Add-Accelerator and Get-Accelerator
        .Link
            http://huddledmasses.org/powershell-2-ctp3-custom-accelerators-finally/
    #>
    
    [CmdletBinding(SupportsShouldProcess=$true)]
    PARAM(
        [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [Alias("Key")]
        [string[]]$Accelerator
    )
    Process 
    {
        
        foreach($a in $Accelerator) {
            foreach($key in $xlr8r::Get.Keys -like $a) { 
                if($PSCmdlet.ShouldProcess( "Removes the alias [$($Key)] for type [$($xlr8r::Get[$key].FullName)]",
                                            "Remove the alias [$($Key)] for type [$($xlr8r::Get[$key].FullName)]?",
                                            "Removing Type Accelerator" )) {
                    # remove a user-defined accelerator
                    $xlr8r::remove($key)   
                }
            }
        }
    
    }
}
    
#endregion 


#region Send-FTP 

function Send-FTP
{
        
    Param(
        [alias('dnsHostName')]
        [Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)]
        [string]$ComputerName = $Env:COMPUTERNAME,
        
        [Parameter()]
        $Credentials = $(Get-Credential),
        
        [Parameter(ValueFromPipeline=$true)]
        $LocalFile,
        
        [Parameter()]
        $Path = "/",
        
        [Parameter()]
        $RemoteFile = $(Split-Path $LocalFile -Leaf),
        
        [Parameter()]
        $ParentProgressId = -1, ## Just ignore this ;)
        
        [Parameter()]
        $ProgressActivity = "Uploading $LocalFile"
    
    )
    Process 
    {
        
        ## Assert the existence of the file in question
        if( -not (Test-Path $LocalFile) ) {
            Throw "File '$LocalFile' does not exist!"
        }
        
        ## Create the server string (and make sure it uses forward slashes and ftp://)
        $upload = "ftp://" + $ComputerName + ( Join-Path (Join-Path "/" $Path) $RemoteFile ) -replace "\\", "/"
        #$Upload = $upload
        $total = (gci $LocalFile).Length
        
        Write-Debug $upload
        ## Create FTP request
        $request = [Net.FtpWebRequest]::Create($upload)
        
        ## NOTE: we do not create a folder here...
        # [System.Net.WebRequestMethods+Ftp]::MakeDirectory
        $request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
        $request.Credentials = $Credentials.GetNetworkCredential()
        $request.UsePassive = $true
        $request.UseBinary = $true
        $request.KeepAlive = $false
        
        try 
        {
            ## Load the file
            $read = [IO.File]::OpenRead( (Convert-Path $LocalFile) )
            $write = $request.GetRequestStream();
            
            $buffer = new-object byte[] 20KB
            $offset = 0
            $progress = 0
        
            do 
            {
                $offset = $read.Read($buffer, 0, $buffer.Length)
                $progress += $offset
                $write.Write($buffer, 0, $offset);
                Write-Progress $ProgressActivity "Uploading" -Percent ([int]($progress/$total * 100)) -Parent $ParentProgressId
            } while($offset -gt 0)
        
        } 
        finally 
        {
            Write-Debug "Closing Handles"
            $read.Close()
            $write.Close()
        }
    
    }
}
    
#endregion 


#region update-Gac 

function update-Gac
{
       
    [AppDomain]::CurrentDomain.GetAssemblies() |
    sort {Split-path $_.location -leaf} | 
    %{
        $Name = (Split-Path $_.location -leaf)
        if ([System.Runtime.InteropServices.RuntimeEnvironment]::FromGlobalAccessCache($_))
        {
            Write-Host "Already GACed: $Name"
        }else
        {
            Write-Host -ForegroundColor Yellow "NGENing      : $Name"
            ngen $_.location | %{"`t$_"}
        }
    }
}
    
#endregion 


#region Out-Voice

function Out-Voice
{
    <#
        .Synopsis  
            Uses speech to read a string(s)
            
        .Description
            Uses speech to read a string(s)
            
        .Parameter Message
            String you want the cmdlet to say
            
        .Example
            Out-Voice "HI There"
            Description
            -----------
            Says "Hi There"
            
        .Example
            Get-DiskSpace | Out-Voice
            Description
            -----------
            Speaks the results of Get-Diskspace
            
        .OUTPUTS
            $null
            
        .Notes
            NAME:      Out-Voice
            AUTHOR:    YetiCentral\bshell
            Website:   www.bsonposh.com
            #Requires -Version 2.0
    #>
    [cmdletbinding()]
    Param(
        [Parameter(ValueFromPipeline=$true)]
        [string]$Message,
        
        [Parameter()]
        [switch]$Passthru
    )
    Begin
    {
        Add-Type -AssemblyName System.Speech
        $Voice = New-Object system.Speech.Synthesis.SpeechSynthesizer 
    }
    Process
    {
        try
        {
            $Voice.SpeakAsync($Message) | Out-Null
            if($Passthru){$_}
        }
        catch
        {
            Write-Host "Unable to play sound"
        }
    }
}

#endregion
